using System;
using System.Data;
using System.Security;
using System.Net;
using System.IO;
using System.Globalization;
using System.ComponentModel;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Xml;
using System.Xml.Serialization;
using System.Xml.Xsl;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.WebPartPages;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.WebPartPages.Communication;

using Core;
using Core.ListViewObjectModel;

namespace FlexListViewer
{
	// TODO: Cache data

	[ToolboxData("<{0}:FlexListViewer runat=server></{0}:FlexListViewer>"),
	XmlRoot(Namespace="FlexListViewer")]
	public class FlexListViewer : WebPart
	{
		#region Public properties
		private string _listUrl = string.Empty;
		[Browsable(true),
		Category("Options"),
		DefaultValue(""),
		WebPartStorage(Storage.Shared),
		FriendlyName("List View Url"),
		Description("Url of a view of the list")]
		public string ListUrl
		{
			get
			{
				return _listUrl;
			}
			set
			{
				_listUrl = value.Trim();

				if (_listUrl.Length > 0)
				{
					// Escape spaces (don't just url-escape, since it may have been escaped already)
					_listUrl = _listUrl.Replace(" ", "%20");
					// Was the url of the list itself instead of the view specified: default to AllItems.aspx.
					if (!_listUrl.ToLower().EndsWith(".aspx"))
					{
						if (!_listUrl.EndsWith("/"))
							_listUrl += "/";
						_listUrl += "AllItems.aspx";
					}
				}
			}
		}

		private string _xsltUrl = string.Empty;
		[Browsable(true),
		Category("Options"),
		DefaultValue(""),
		WebPartStorage(Storage.Shared),
		FriendlyName("Xslt Url"),
		Description("Url to the Xslt-file which renders the HTML.")]
		public string XsltUrl
		{
			get
			{
				return _xsltUrl;
			}
			set
			{
				_xsltUrl = value;
			}
		}

		private const string DEFAULT_MSG_ADDNEWITEM = "Add a new item";
		private string _msgAddNewItem = DEFAULT_MSG_ADDNEWITEM;
		[Browsable(true),
		Category("Messages"),
		DefaultValue(DEFAULT_MSG_ADDNEWITEM),
		WebPartStorage(Storage.Shared),
		FriendlyName("Message"),
		Description("Title of the 'add new item'-link.")]
		public string MsgAddNewItem
		{
			get
			{
				return _msgAddNewItem;
			}
			set
			{
				_msgAddNewItem = value;
			}
		}

		private const string DEFAULT_MSG_YES = "Yes";
		private string _msgYes = DEFAULT_MSG_YES;
		[Browsable(true),
		Category("Messages"),
		DefaultValue(DEFAULT_MSG_YES),
		WebPartStorage(Storage.Shared),
		FriendlyName("'Yes'-message"),
		Description("Text to be displayed for the boolean value 'True'")]
		public string MsgYes
		{
			get
			{
				return _msgYes;
			}
			set
			{
				_msgYes = value;
			}
		}

		private const string DEFAULT_MSG_NO = "No";
		private string _msgNo = DEFAULT_MSG_NO;
		[Browsable(true),
		Category("Messages"),
		DefaultValue(DEFAULT_MSG_NO),
		WebPartStorage(Storage.Shared),
		FriendlyName("'No'-message"),
		Description("Text to be displayed for the boolean value 'False'")]
		public string MsgNo
		{
			get
			{
				return _msgNo;
			}
			set
			{
				_msgNo = value;
			}
		}
		
		private const bool DEFAULT_ALLOWADDNEWITEM = true;
		private bool _allowAddNewItem = DEFAULT_ALLOWADDNEWITEM;
		[Browsable(true),
		Category("Options"),
		DefaultValue(DEFAULT_ALLOWADDNEWITEM),
		WebPartStorage(Storage.Shared),
		FriendlyName("'Add new item' enabled"),
		Description("Specifies whether the 'Add new item'-link is displayed.")]
		public bool AllowAddNewItem
		{
			get
			{
				return _allowAddNewItem;
			}
			set
			{
				_allowAddNewItem = value;
			}
		}
		
		private const bool DEFAULT_DISPLAYXML = false;
		private bool _displayXML = DEFAULT_DISPLAYXML;
		[Browsable(true),
		Category("Options"),
		DefaultValue(DEFAULT_DISPLAYXML),
		WebPartStorage(Storage.Shared),
		FriendlyName("Display XML (for debugging purposes)"),
		Description("Specifies whether the composed XML must be displayed.")]
		public bool DisplayXML
		{
			get
			{
				return _displayXML;
			}
			set
			{
				_displayXML = value;
			}
		}

		#region Parameter-properties
		private string[] _params = new string[5];
		[Browsable(true),
		Category("Parameters"),
		DefaultValue(""),
		WebPartStorage(Storage.Shared),
		FriendlyName("Parameter 1"),
		Description("Parameter to send to xslt.")]
		public string Param1
		{
			get
			{
				return _params[0];
			}
			set
			{
				_params[0] = value;
			}
		}
		[Browsable(true),
		Category("Parameters"),
		DefaultValue(""),
		WebPartStorage(Storage.Shared),
		FriendlyName("Parameter 2"),
		Description("Parameter to send to xslt.")]
		public string Param2
		{
			get
			{
				return _params[1];
			}
			set
			{
				_params[1] = value;
			}
		}
		[Browsable(true),
		Category("Parameters"),
		DefaultValue(""),
		WebPartStorage(Storage.Shared),
		FriendlyName("Parameter 3"),
		Description("Parameter to send to xslt.")]
		public string Param3
		{
			get
			{
				return _params[2];
			}
			set
			{
				_params[2] = value;
			}
		}
		[Browsable(true),
		Category("Parameters"),
		DefaultValue(""),
		WebPartStorage(Storage.Shared),
		FriendlyName("Parameter 4"),
		Description("Parameter to send to xslt.")]
		public string Param4
		{
			get
			{
				return _params[3];
			}
			set
			{
				_params[3] = value;
			}
		}
		[Browsable(true),
		Category("Parameters"),
		DefaultValue(""),
		WebPartStorage(Storage.Shared),
		FriendlyName("Parameter 5"),
		Description("Parameter to send to xslt.")]
		public string Param5
		{
			get
			{
				return _params[4];
			}
			set
			{
				_params[4] = value;
			}
		}
		#endregion		
		#endregion

		protected override void RenderWebPart(HtmlTextWriter output)
		{
			if (ListUrl.Trim().Equals(string.Empty))
			{
				output.Write("Please configure the URL for the list to be displayed.");
				return;
			}

			SPView view;

			try
			{
				// Get reference to the SPView
				view = SPListUtil.GetViewForUrl(ListUrl,Context);
				if (view == null)
					throw (new ArgumentException("Non-existing list or view specified.", "List Url"));
			}
			catch (Exception ex)
			{
				output.WriteLine ("Cannot access the view of the list. Are you authorized?<br/>");
				output.WriteLine ("Details: " + ex.Message);
				return;
			}

			try
			{
				// Generate an objectmodel from the view
                Core.ListViewObjectModel.ListView listView = SPListUtil.GenerateListViewObjectModel(view);

				// Serialize the objectmodel to XML
                XmlDocument docListXml = XMLUtil.SerializeObjectModel(listView, typeof(Core.ListViewObjectModel.ListView));

				if (_displayXML)
				{
					output.WriteLine (Page.Server.HtmlEncode(docListXml.InnerXml) + "<br/>");
				}

				// Load the XSLT to transform the XML to HTML
				XmlDocument docListXsl = new XmlDocument();
				try
				{
					string xsltCode = FileUtil.LoadDocument((_xsltUrl.Length > 0) ? _xsltUrl : ClassResourcePath + "/" + "StandardList.xslt", Context);
					docListXsl.LoadXml(xsltCode);
				}
				catch (Exception ex)
				{
					output.WriteLine ("Cannot read the specified Xslt-file.<br/>");
					output.WriteLine ("Details: " + ex.Message);
					return;
				}

				// DEBUG
				//output.Write("Xslt:[" + ((_xsltUrl.Length > 0) ? _xsltUrl : ClassResourcePath + "/" + "StandardList.xslt") + "]");

				// Perform the transformation
				SPWeb web = SPControl.GetContextWeb(Context);
				XsltArgumentList args = new XsltArgumentList();
				args.AddParam("currentPage", "", Page.Request.Url.AbsoluteUri);
				args.AddParam("currentSiteUrl", "", web.Url + "/");
				args.AddParam("lcid", "", web.Language.ToString());
				args.AddParam("allowAddNewItem", "", _allowAddNewItem.ToString());
				args.AddParam("msgAddNewItem", "", _msgAddNewItem);
				args.AddParam("msgYes", "", (_msgYes.Length > 0) ? _msgYes : Microsoft.SharePoint.Strings.Yes);
				args.AddParam("msgNo", "", (_msgNo.Length > 0) ? _msgNo : Microsoft.SharePoint.Strings.No);
				for (int paramCount = 0;paramCount < _params.Length;paramCount++)
				{
					string paramValue = (_params[paramCount] != null) ? _params[paramCount] : string.Empty;
					args.AddParam("param" + (paramCount+1).ToString(CultureInfo.InvariantCulture), "", paramValue);
				}

				string html = XMLUtil.TransformXml(docListXml, docListXsl, args, this.GetType().Assembly.Evidence);

				// Write the HTML to the output
				output.Write (html);
			}
			catch (Exception ex)
			{
				// Display the exception
				output.WriteLine("Error occurred: " + ex.Message + "<br/>");
				output.WriteLine("Details: " + ex.ToString() + "<br/>" + ex.StackTrace);
			}

			base.RenderWebPart (output);
		}
	}
}
